package com.mtw.bbs.reply.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mtw.bbs.common.core.util.ExecutorUtilz;
import com.mtw.bbs.common.redisBase.util.TimeUtilz;
import com.mtw.bbs.constant.ReplyConstant;
import com.mtw.bbs.reply.mapper.ReplySubjectMapper;
import com.mtw.bbs.reply.pojo.entity.ReplySubject;
import com.mtw.bbs.reply.pojo.form.ReplyForm;
import com.mtw.bbs.reply.service.ReplySubjectService;
import com.mtw.bbs.common.core.constant.SysConstant;
import com.mtw.bbs.common.redisBase.util.RedisUtilz;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.*;

import static com.mtw.bbs.common.core.constant.RedisConstant.NAME_SPACE;

/**
 * 评论区
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ReplySubjectServiceImpl extends ServiceImpl<ReplySubjectMapper, ReplySubject> implements ReplySubjectService {

    private final ExecutorUtilz executorUtilz;
    private final RedissonClient redissonClient;
    private final RedisUtilz<String, Object> redisUtilz;


    /**
     * 获取或新增评论区
     */
    @Override
    public ReplySubject saveOrGetReplySubject(ReplyForm form) {


        // 缓存是否存在
        ReplySubject replySubject = getReplySubject(form.getObjectType(), form.getObjectId());
        if (replySubject != null) {
            return replySubject;
        }

        String lockKey = ReplyConstant.LOCK_REPLY_SUBJECT_PREFIX + form.getObjectType() + "_" + form.getObjectId();
        RLock lock = redissonClient.getLock(lockKey);
        lock.lock();
        try {
            replySubject = getReplySubject(form.getObjectType(), form.getObjectId());
            // 新增
            return Objects.requireNonNullElseGet(replySubject, () -> this.doSave(form));
        } finally {
            lock.unlock();
        }
    }


    /**
     * 获取评论区id
     */
    @Override
    public ReplySubject getReplySubject(String objectType, String objectId) {

        // 缓存是否存在
        String redisKey = ReplyConstant.REDIS_REPLY_SUBJECT_PREFIX + objectType + "_" + objectId;
        ReplySubject subject = (ReplySubject) redisUtilz.get(redisKey);
        if (subject != null) {
            return subject;
        }

        LambdaQueryWrapper<ReplySubject> lqw = new LambdaQueryWrapper<>();
        lqw.select(ReplySubject::getId, ReplySubject::getStatus, ReplySubject::getObjectId, ReplySubject::getObjectType);
        lqw.eq(ReplySubject::getObjectType, objectType);
        lqw.eq(ReplySubject::getObjectId, objectId);
        List<ReplySubject> list = list(lqw);

        if (list.isEmpty()) {
            return null;
        }
        subject = list.get(0);
        redisUtilz.set(redisKey, subject,Duration.ofMinutes(30+ TimeUtilz.getRandomMinutes()));
        return subject;
    }


    /**
     * 获取评论区评论数量
     */
    @Override
    public Integer getRelyCount(String objectType, String objectId) {

        String redisKey = ReplyConstant.REDIS_REPLY_COUNT_PREFIX + objectType + NAME_SPACE + objectId;
        Integer iCount =  (Integer)redisUtilz.get(redisKey);
        if (iCount != null){
            return iCount;
        }
        LambdaQueryWrapper<ReplySubject> lqw = new LambdaQueryWrapper<>();
        lqw.select(ReplySubject::getReplyCount);
        lqw.eq(ReplySubject::getObjectType, objectType);
        lqw.eq(ReplySubject::getObjectId, objectId);
        List<ReplySubject> list = list(lqw);
        Integer count = list.isEmpty()?0:list.get(0).getReplyCount();
        redisUtilz.set(redisKey,count, Duration.ofSeconds(600+ TimeUtilz.getRandomSecond()));
        return count;
    }


    /**
     * 获取评论区评论数量
     */
    @Override
    public Map<String, Integer> getRelyCountByIds(String objectType, Collection<String> objectIds) {
        Map<String, Integer> map = new HashMap<>(objectIds.size());
        objectIds.forEach(x -> map.put(x, getRelyCount(objectType, x)));
        return map;
    }


    /**
     * 保存
     */
    private ReplySubject doSave(ReplyForm form) {

        String redisKey = ReplyConstant.REDIS_REPLY_COUNT_PREFIX + form.getObjectType() + "_" + form.getObjectId();
        redisUtilz.delete(redisKey);
        ReplySubject entity = new ReplySubject();
        entity.setObjectId(form.getObjectId());
        entity.setObjectType(form.getObjectType());
        entity.setReplyCount(0);
        entity.setStatus(SysConstant.DEFAULT_ENABLE);
        this.save(entity);
        executorUtilz.delayedTask(()-> redisUtilz.delete(redisKey));
        return entity;
    }
}
